package com.myhome.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.myhome.config.IdAutoConfig;
import com.myhome.config.constant.R;
import com.myhome.domain.Sms;
import com.myhome.domain.UserAuthAuditRecord;
import com.myhome.domain.UserAuthForm;
import com.myhome.dto.UserDto;
import com.myhome.geetest.GeetestLib;
import com.myhome.mappers.UserDtoMapper;
import com.myhome.model.*;
import com.myhome.service.SmsService;
import com.myhome.service.UserAuthAuditRecordService;
import org.reflections.util.Utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.myhome.domain.User;
import com.myhome.mapper.UserMapper;
import com.myhome.service.UserService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

/**
*@Author QYiXin 
* @Date 2021 10 13 10 51
**/
@Service
@Transactional
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService{
    @Autowired
    UserAuthAuditRecordService userAuthAuditRecordService;
    @Autowired
    GeetestLib geetestLib;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    SmsService smsService;

    @Override
    public Page<User> getPagesUsers(Page<User> page, String mobile, Long userId,
                                    String userName, String realName, Byte status) {
        return this.page(page, new LambdaQueryWrapper<User>().like(!StringUtils.isEmpty(mobile), User::getMobile, mobile).
                like(!StringUtils.isEmpty(userName), User::getUsername, userName).
                like(!StringUtils.isEmpty(realName), User::getRealName, realName).
                eq(!ObjectUtils.isEmpty(status), User::getStatus, status).
                eq(!ObjectUtils.isEmpty(userId), User::getId, userId)
        );
    }

    @Override
    public Page<User> getInvitedPerson(Page<User> page, Long userId) {
        return this.page(page, new LambdaQueryWrapper<User>().eq(User::getDirectInviteid, userId));
    }

    @Override
    public Page<User> getPagesAuth(Page<User> page, String mobile, Long userId, String userName, String realName, Byte reviewsStatus) {
        return this.page(page, new LambdaQueryWrapper<User>().like(!StringUtils.isEmpty(mobile), User::getMobile, mobile).
                like(!StringUtils.isEmpty(userName), User::getUsername, userName).
                like(!StringUtils.isEmpty(realName), User::getRealName, realName).
                like(!StringUtils.isEmpty(mobile), User::getMobile, mobile).
                eq(!ObjectUtils.isEmpty(userId), User::getId, userId).
                eq(!ObjectUtils.isEmpty(reviewsStatus), User::getReviewsStatus, reviewsStatus)
        );
    }

    @Override
    public boolean updateAuthStatus(Long id, Byte authStatus, Long authCode, String remark) {
        User user = this.getById(id);
        user.setReviewsStatus(Integer.valueOf(authStatus));
        this.updateById(user);
        boolean isSave = true;
        if (authStatus != 0) {
            UserAuthAuditRecord userAuthAuditRecord = new UserAuthAuditRecord();
            userAuthAuditRecord.setUserId(id);
            userAuthAuditRecord.setAuthCode(authCode);
            userAuthAuditRecord.setStatus(authStatus);
            String auditId = SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString();
            userAuthAuditRecord.setAuditUserId(Long.valueOf(auditId));
            userAuthAuditRecord.setAuditUserName("------------------");
            userAuthAuditRecord.setCreated(new Date());
            userAuthAuditRecord.setRemark(remark);
            isSave = userAuthAuditRecordService.save(userAuthAuditRecord);
        }
        return isSave;
    }

    @Override
    public User getUserByMobileOrEmail(String username) {
        return this.getOne(new LambdaQueryWrapper<User>().eq(User::getMobile, username).or().eq(User::getEmail, username));
    }

    @Override
    public Boolean checkAuth(Long userId, UserAuthForm userAuthForm) {
        User user = this.getById(userId);
        if (ObjectUtils.isEmpty(user)) {
            throw new AuthenticationServiceException("无该用户");
        }
        Byte authStatus = user.getAuthStatus();
        if (!authStatus.equals((byte)0)) {
            throw new IllegalArgumentException("该用户已认证");
        }
        //checkGeetestForm(userAuthForm);
        boolean isOk = IdAutoConfig.checkUserId(userAuthForm.getRealName(), userAuthForm.getIdCard());
        if (isOk) {
            user.setAuthStatus(Byte.valueOf((byte)(1)));
            user.setIdCard(userAuthForm.getIdCard());
            user.setRealName(userAuthForm.getRealName());
            user.setIdCardType(userAuthForm.getIdCardType());
            this.save(user);
            return true;
        }
        return false;
    }

    @Override
    public Boolean updatePhone(Long userId,NewPhoneAndOldPhone newPhoneAndOldPhone) {
        User user = this.getById(userId);
        if (user == null) {
            throw new IllegalArgumentException("用户不存在");
        }
        String mobile = user.getMobile();
        String oldCode = (String) redisTemplate.opsForValue().get("SMS" + user.getMobile() + "CODE");
        if (!newPhoneAndOldPhone.getOldValidateCode().equals(oldCode)) {
            throw new IllegalArgumentException("验证码不正确");
        }
        String newCode = (String) redisTemplate.opsForValue().get("SMS" + newPhoneAndOldPhone.getNewMobilePhone() + "CODE");
        if (!newCode.equals(newPhoneAndOldPhone.getValidateCode())) {
            throw new IllegalArgumentException("验证码不正确");
        }
        user.setMobile(newPhoneAndOldPhone.getNewMobilePhone());
        return this.updateById(user);
    }

    @Override
    public Boolean checkNewPhone(String mobile, String countryCode) {
        List<User> list = this.list(new LambdaQueryWrapper<User>().eq(User::getMobile, mobile).eq(User::getCountryCode, countryCode));
        if (!list.isEmpty() || list.size() != 0) {
            throw new IllegalArgumentException("该手机号不可用");
        }
        Sms sms = new Sms();
        sms.setMobile(mobile);
        sms.setCountryCode(countryCode);
        return smsService.sendMessage(sms);
    }

    @Override
    public Boolean updateLoginPassword(Long userId, UpdatePasswordInfo updatePasswordInfo) {
        User user = this.getById(userId);
        String code = (String) redisTemplate.opsForValue().get("SMS" + user.getMobile() + "CODE");
        if (!code.equals(updatePasswordInfo.getValidateCode())) {
            throw new IllegalArgumentException("验证码错误");
        }
        if (ObjectUtils.isEmpty(user)) {
            throw new IllegalArgumentException("该用户不存在");
        }
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        boolean isMatches = encoder.matches(updatePasswordInfo.getOldpassword(), user.getPassword());
        if (!isMatches) {
            throw new IllegalArgumentException("旧密码不正确");
        }
        user.setPassword(encoder.encode(updatePasswordInfo.getNewpassword()));
        return this.updateById(user);

    }

    @Override
    public Boolean updatePayPassword(Long userId, UpdatePasswordInfo updatePasswordInfo) {
        System.out.println(userId);
        User user = this.getById(userId);
        /*
         * 验证码验证暂时不实现
         * */
        String code = (String) redisTemplate.opsForValue().get("SMS" + user.getMobile() + "CODE");
        if (!code.equals(updatePasswordInfo.getValidateCode())) {
            throw new IllegalArgumentException("验证码错误");
        }
        if (ObjectUtils.isEmpty(user)) {
            throw new IllegalArgumentException("该用户不存在");
        }
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        boolean isMatches = encoder.matches(updatePasswordInfo.getOldpassword(), user.getPassword());
        if (!isMatches) {
            throw new IllegalArgumentException("旧密码不正确");
        }
        user.setPassword(encoder.encode(updatePasswordInfo.getNewpassword()));
        return this.updateById(user);
    }
    @Override
    public Boolean unsetPassword(Long userId, UnsetPasswordInfo unsetPasswordInfo) {
        User user = this.getById(userId);
        if (ObjectUtils.isEmpty(user)) {
            throw new IllegalArgumentException("该用户不存在");
        }
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        user.setPaypassword(encoder.encode(unsetPasswordInfo.getPayPassword()));
        return this.updateById(user);
    }

    @Override
    public List<User> getInvitedPeron() {
        Long userId = Long.valueOf(SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
        List<User> result = this.list(new LambdaQueryWrapper<User>().eq(User::getDirectInviteid, userId));
        return result == null ? Collections.emptyList() : result;
    }

    @Override
    public List<UserDto> getManyUsers(List<Long> ids) {
        if (CollectionUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        List<User> userList = this.list(new LambdaQueryWrapper<User>().in(User::getId, ids));
        return ((userList == null) ? Collections.emptyList() : UserDtoMapper.INSTANCE.convert2Dto(userList));
    }

    @Override
    public boolean register(RegisterParam registerParam) {
        if (StringUtils.isEmpty(registerParam.getEmail()) && StringUtils.isEmpty(registerParam.getMobile())) {
            throw new IllegalArgumentException("手机号和邮箱不能同时为空");
        }
        List<User> userList = this.list(new LambdaQueryWrapper<User>()
                .eq(!StringUtils.isEmpty(registerParam.getMobile()), User::getMobile, registerParam.getMobile())
                .eq(StringUtils.isEmpty(registerParam.getEmail()), User::getEmail, registerParam.getEmail()));
        if (userList.size() > 0) {
            throw new IllegalArgumentException("手机号或邮箱已经被占用");
        }
        String validateCode =(String) redisTemplate.opsForValue().get("SMS" + registerParam.getMobile() + "CODE");
        User user = new User();
        user.setMobile(registerParam.getMobile());
        user.setEmail(registerParam.getEmail());
        user.setPassword(new BCryptPasswordEncoder().encode(registerParam.getPassword()));
        user.setAuthStatus((byte) 0);
        user.setReviewsStatus(0);
        User invitedPerson = this.getOne(new LambdaQueryWrapper<User>().eq(StringUtils.isEmpty(registerParam.getInvitionCode()), User::getInviteCode, registerParam.getInvitionCode()));
        user.setDirectInviteid(String.valueOf(invitedPerson==null?null:invitedPerson.getId()));
        user.setInviteRelation(String.valueOf(invitedPerson==null?null:invitedPerson.getId()));
        user.setInviteCode(RandomUtil.randomNumbers(8));
        return this.save(user);
    }

    @Override
    public Boolean publicSetPassword(PublicSetPasswordParam publicSetPasswordParam) {
        User user = this.getOne(new LambdaQueryWrapper<User>().eq(User::getMobile, publicSetPasswordParam.getMobile()));
        if (user == null) {
            throw new IllegalArgumentException("不存在该用户");
        }
        String validateCode = (String) redisTemplate.opsForValue().get("SMS" + publicSetPasswordParam.getMobile() + "CODE");
        if (!publicSetPasswordParam.getValidateCode().equals(validateCode)) {
            throw new IllegalArgumentException("验证码错误");
        }
        user.setPassword(new BCryptPasswordEncoder().encode(publicSetPasswordParam.getPassword()));
        return this.updateById(user);
    }

    @Override
    public Map<Long, UserDto> getBasicMapUserDto(List<Long> ids, String userName, String mobile) {
        /*if (CollectionUtil.isEmpty(ids) && StringUtils.isEmpty(userName) && StringUtils.isEmpty(mobile)) {
            return Collections.emptyMap();
        }
        List<User> userList = this.list(new LambdaQueryWrapper<User>().in(!CollectionUtil.isEmpty(ids), User::getId, ids)
                .like(!StringUtils.isEmpty(userName),User::getUsername, userName)
                .like(!StringUtils.isEmpty(mobile),User::getMobile, mobile)
        );
        if (CollectionUtil.isEmpty(userList)) {
            return Collections.emptyMap();
        }
        List<UserDto> userDtoList = UserDtoMapper.INSTANCE.convert2Dto(userList);
        return userDtoList.stream().collect(Collectors.toMap(UserDto::getId, userDto -> userDto));
    }

    private void checkGeetestForm(UserAuthForm userAuthForm) {
        UserAuthForm.checkGeetestForm(geetestLib, redisTemplate, userAuthForm);*/
        if (CollectionUtil.isEmpty(ids) && StringUtils.isEmpty(userName) && StringUtils.isEmpty(mobile)) {
            return Collections.emptyMap();
        }
        List<User> list = list(new LambdaQueryWrapper<User>()
                .in(!CollectionUtil.isEmpty(ids), User::getId, ids)
                .like(!StringUtils.isEmpty(userName), User::getUsername, userName)
                .like(!StringUtils.isEmpty(mobile), User::getMobile, mobile));
        if (CollectionUtil.isEmpty(list)) {
            return Collections.emptyMap();
        }
        // 将user->userDto
        List<UserDto> userDtos = UserDtoMapper.INSTANCE.convert2Dto(list);
        Map<Long, UserDto> userDtoMaps = userDtos.stream().collect(Collectors.toMap(UserDto::getId, userDto -> userDto));
        return userDtoMaps;
    }
}
